/*
 * NativeTestCase.java  0.4.0 / Oct 25, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
package com.cute4j.nunit;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

import com.cute4j.Cute4j;

/**
 * Native Tests.
 *
 * @cute4j.native
 *    generate="header"
 *
 * @author Slobodan Vrkacevic
 * @version 0.4.0
 */
public final class NativeTest extends TestCase { // NOPMD

// Private Static Fields. ------------------------------------------------------

  private static TestSuite nativeTests;

// Static Initialization. ------------------------------------------------------

  static {
    Cute4j.initialize();
    _initialize();
  }

// Package-Private Field. ------------------------------------------------------

  final String moduleName;
  final String testCaseName;
  final long _testCase;

// Package-Private Constructor. ------------------------------------------------

  NativeTest(String moduleName, String testCaseName, String methodName,
             long testCase) {
    super(methodName);
    this.moduleName = moduleName;
    this.testCaseName = testCaseName;
    _testCase = testCase;
  }

// Public Static Method. -------------------------------------------------------

  /**
   * Returns all native tests.
   *
   * @return all native tests
   */
  public static Test getNativeTests() {
    if (nativeTests == null) { // NOPMD
      nativeTests = new TestSuite("native code");
      String[] testModules = _getTestModules();
      for (int i = 0; i < testModules.length; i++) {
        String testModuleName = testModules[i];
        TestSuite nativeModuleTest = new TestSuite(testModuleName);
        String[] moduleTestCases = _getTestCases(testModuleName);
        for (int j = 0; j < moduleTestCases.length; j++) {
          String testCaseName = moduleTestCases[j];
          TestSuite nativeTestCase = new ExecTestSuite(testCaseName);
          long testCase = _createTestCase(testModuleName, testCaseName);
          String[] tests = _getTests(testCase);
          for (int k = 0; k < tests.length; k++) {
            nativeTestCase.addTest(new NativeTest(testModuleName, testCaseName,
                                                  tests[k], testCase));
          }
          nativeModuleTest.addTest(nativeTestCase);
        }
        nativeTests.addTest(nativeModuleTest);
      }
    }
    return nativeTests;
  }

// Package-Private Static Methods. ---------------------------------------------

  static Test findTest(String moduleName, String testCaseName,
                       String testName) {
    TestSuite tests = (TestSuite)getNativeTests();
    for (int i = 0; i < tests.testCount(); i++) {
      TestSuite nativeModuleTest = (TestSuite)tests.testAt(i);
      if (moduleName.equals(nativeModuleTest.getName())) {
        for (int j = 0; j < nativeModuleTest.testCount(); j++) {
          TestSuite nativeTestCase = (TestSuite)nativeModuleTest.testAt(j);
          if (testCaseName.equals(nativeTestCase.getName())) {
            for (int k = 0; k < nativeTestCase.testCount(); k++) {
              NativeTest nativeTest = (NativeTest)nativeTestCase.testAt(k);
              if (testName.equals(nativeTest.getName())) { // NOPMD
                return nativeTest;
              }
            }
            break;
          }
        }
        break;
      }
    }
    return null;
  }

// Package-Private Methods. ----------------------------------------------------
  
  /**
   * Fails native test.
   *
   * @param condition the condition
   * @param fileName the file name
   * @param lineNumber the line number
   */
  void failCondition(String condition, String fileName, int lineNumber) {
    fail(formatMessage(condition, fileName, lineNumber));
  }

  /**
   * Formats error message.
   *
   * @param condition the condition
   * @param fileName the file name
   * @param lineNumber the line number
   *
   * @return formatted error message.
   */
  String formatMessage(String condition, String fileName, int lineNumber) {
    StringBuffer sb;
    if (condition == null) {
      sb = new StringBuffer("Native condition failed");
    } else {
      sb = new StringBuffer("Native condition \"");
      sb = sb.append(condition);
      sb.append("\" failed");
    }
    if (fileName != null) {
      sb.append("\n in file: ");
      sb.append(fileName);
    }
    if (lineNumber >= 0) {
      sb.append("\n at line: ");
      sb.append(lineNumber);
    }
    return sb.toString();
  }

// Overridden Methods. ---------------------------------------------------------

  /**
   * {@inheritDoc}
   */
  protected void setUp() throws Exception {
    if (_testCase == 0) {
      fail("Null native test case");
    }
    _setUp(_testCase);
  }

  /**
   * {@inheritDoc}
   */
  protected void tearDown() throws Exception {
    if (_testCase == 0) {
      fail("Null native test case");
    }
    _tearDown(_testCase);
  }

  /**
   * {@inheritDoc}
   */
  protected void runTest() throws Throwable {
    if (_testCase == 0) {
      fail("Null native test case");
    }
    if (!_invokeMethod(_testCase, getName())) {
      fail("Native method call failed");
    }
  }

// Package-Private Native Methods. ---------------------------------------------

  native void _setUp(long testCase);

  native void _tearDown(long testCase);

  native boolean _invokeMethod(long testCase, String methodName);

// Private Static Native Methods. ----------------------------------------------

  private static native String[] _getTestModules();

  private static native String[] _getTestCases(String testModule);

  private static native long _createTestCase(String testModule,
                                             String testCase);

  private static native String[] _getTests(long testCase);

  private static native void _initialize();

}
